<!doctype html>



  


<html class="theme-next muse use-motion">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  
  
  <link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.0.1" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="java," />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.0.1" />






<meta name="description" content="Java中一个类若是要被使用，必然经过加载以及初始化的过程。这里我们来研究一下一个类是如何被加载的，以及加载类时可能会出现的异常


类加载器简介
自定义类加载器
加载过程中可能会出现的异常
Class的加载过程
总结">
<meta property="og:type" content="article">
<meta property="og:title" content="个人博客">
<meta property="og:url" content="http://yoursite.com/2016/08/28/java-class-load/index.html">
<meta property="og:site_name" content="个人博客">
<meta property="og:description" content="Java中一个类若是要被使用，必然经过加载以及初始化的过程。这里我们来研究一下一个类是如何被加载的，以及加载类时可能会出现的异常


类加载器简介
自定义类加载器
加载过程中可能会出现的异常
Class的加载过程
总结">
<meta property="og:image" content="http://hi.csdn.net/attachment/201009/25/0_1285421756PHyZ.gif">
<meta property="og:updated_time" content="2017-01-19T07:14:12.816Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="个人博客">
<meta name="twitter:description" content="Java中一个类若是要被使用，必然经过加载以及初始化的过程。这里我们来研究一下一个类是如何被加载的，以及加载类时可能会出现的异常


类加载器简介
自定义类加载器
加载过程中可能会出现的异常
Class的加载过程
总结">
<meta name="twitter:image" content="http://hi.csdn.net/attachment/201009/25/0_1285421756PHyZ.gif">



<script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Muse',
    sidebar: {"position":"left","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: 0,
      author: '博主'
    }
  };
</script>




  <link rel="canonical" href="http://yoursite.com/2016/08/28/java-class-load/"/>

  <title>  | 个人博客 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  










  
  
    
  

  <div class="container one-collumn sidebar-position-left page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">个人博客</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">随便写点什么</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      

      
    </ul>
  

  
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">发表于</span>
            <time itemprop="dateCreated" datetime="2016-08-28T15:46:02+08:00" content="2016-08-28">
              2016-08-28
            </time>
          </span>

          
            <span class="post-category" >
              &nbsp; | &nbsp;
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="https://schema.org/Thing">
                  <a href="/categories/java/" itemprop="url" rel="index">
                    <span itemprop="name">java</span>
                  </a>
                </span>

                
                

              
            </span>
          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/08/28/java-class-load/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/08/28/java-class-load/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          

          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>Java中一个类若是要被使用，必然经过加载以及初始化的过程。<br>这里我们来研究一下一个类是如何被加载的，以及加载类时可能会出现的异常</p>
<blockquote>
<ul>
<li>类加载器简介</li>
<li>自定义类加载器</li>
<li>加载过程中可能会出现的异常</li>
<li>Class的加载过程</li>
<li>总结</li>
</ul>
</blockquote>
<hr>
<a id="more"></a>
<h2 id="1-类的加载器简介"><a href="#1-类的加载器简介" class="headerlink" title="1.类的加载器简介"></a>1.类的加载器简介</h2><p>一般加载器分为四级：引导类加载器，扩展类加载器，系统类加载器，用户自定义加载器。</p>
<blockquote>
<p>通常：<br>    系统类加载器：加载我们自己写的java文件。<br>    扩展类加载器：一些导入的jar包。<br>    引导类加载器：java运行所需的一些核心类。<br>    自定义加载器：用户自己创建用以加载指定类的加载器。</p>
</blockquote>
<p><img src="http://hi.csdn.net/attachment/201009/25/0_1285421756PHyZ.gif" alt=""></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//一个打印出加载器之间的层级关系的小demo</span></div><div class="line"> <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassLoaderTree</span> </span>&#123; </div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123; </div><div class="line">        ClassLoader loader = ClassLoaderTree.class.getClassLoader(); </div><div class="line">        <span class="keyword">while</span> (loader != <span class="keyword">null</span>) &#123; </div><div class="line">            System.out.println(loader.toString()); </div><div class="line">            loader = loader.getParent(); </div><div class="line">        &#125; </div><div class="line">    &#125; </div><div class="line"> &#125;</div></pre></td></tr></table></figure>
<p>output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">//至于这里没有显示引导类加载器，是因为JDK的自身实现，当获取引导类加载器的时候，返回null。</div><div class="line">sun.misc.Launcher$AppClassLoader@4edde6e5</div><div class="line">sun.misc.Launcher$ExtClassLoader@79fc0f2f</div></pre></td></tr></table></figure></p>
<h2 id="2-自定义类加载器"><a href="#2-自定义类加载器" class="headerlink" title="2.自定义类加载器"></a>2.自定义类加载器</h2><p>虽然在绝大多数情况下，系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下，我们还是需要为应用开发出自己的类加载器以满足一些特殊需求。<br>通常的，自定义类加载器是以继承ClassLoader，但通常是用继承URLClassLoader来实现的。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyClassLoader</span> <span class="keyword">extends</span> <span class="title">ClassLoader</span> </span>&#123; </div><div class="line"></div><div class="line">    <span class="keyword">protected</span> Class&lt;?&gt; findClass(String name) <span class="keyword">throws</span> ClassNotFoundException &#123; </div><div class="line">        <span class="keyword">byte</span>[] data = getClassData(name); </div><div class="line">        <span class="keyword">if</span> (data == <span class="keyword">null</span>) &#123; </div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ClassNotFoundException(); </div><div class="line">        &#125; </div><div class="line">        <span class="keyword">else</span> &#123; </div><div class="line"><span class="comment">//一般的类加载，我们是提供类名，或者一个路径，让加载器去读取类的字节码，defineClass的功能是将获取到的类的字节码进行加载，我们需要提供类的字节码。</span></div><div class="line">            <span class="keyword">return</span> defineClass(name, classData, <span class="number">0</span>, classData.length); </div><div class="line">        &#125; </div><div class="line">    &#125; </div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">byte</span>[] getClassData(String className) &#123; </div><div class="line">        String path = classNameToPath(className); </div><div class="line">        <span class="keyword">try</span> &#123; </div><div class="line">            InputStream ins = <span class="keyword">new</span> FileInputStream(path); </div><div class="line">            ByteArrayOutputStream baos = <span class="keyword">new</span> ByteArrayOutputStream(); </div><div class="line">            <span class="keyword">int</span> bufferSize = <span class="number">4096</span>; </div><div class="line">            <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[bufferSize]; </div><div class="line">            <span class="keyword">int</span> bytesNumRead = <span class="number">0</span>; </div><div class="line">            <span class="keyword">while</span> ((bytesNumRead = ins.read(buffer)) != -<span class="number">1</span>) &#123; </div><div class="line">                baos.write(buffer, <span class="number">0</span>, bytesNumRead); </div><div class="line">            &#125; </div><div class="line">            <span class="keyword">return</span> baos.toByteArray(); </div><div class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123; </div><div class="line">            e.printStackTrace(); </div><div class="line">        &#125; </div><div class="line">        <span class="keyword">return</span> <span class="keyword">null</span>; </div><div class="line">    &#125; </div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">classNameToPath</span><span class="params">(String path, String className)</span> </span>&#123; </div><div class="line">        <span class="keyword">return</span> path + File.separatorChar </div><div class="line">                + className.replace(<span class="string">'.'</span>, File.separatorChar) + <span class="string">".class"</span>; </div><div class="line">    &#125; </div><div class="line"> &#125;</div><div class="line"> <span class="comment">//加载完后，若加载成功，拿到Class对象，可以用newInstance()方法将其实例化后就可使用。</span></div></pre></td></tr></table></figure></p>
<p>之所以继承ClassLoader是因为我们要自己实现在加载一个类的话，需要调用ClassLoader中的一些函数，而这些函数是protected的。就比如上面的defineClass()。<br>这样，我们就简单的实现了一个自定义的类加载器。<br>这里先提个问题：<br>我们用以上方式得到的Class对象进行实例化后，如果对其进行例如A a = (A)o；这样的类型转换，会抛出异常么？</p>
<hr>
<h2 id="3-加载过程中可能会出现的异常"><a href="#3-加载过程中可能会出现的异常" class="headerlink" title="3.加载过程中可能会出现的异常"></a>3.加载过程中可能会出现的异常</h2><h3 id="1-ClassNotFoundException"><a href="#1-ClassNotFoundException" class="headerlink" title="1.ClassNotFoundException"></a>1.ClassNotFoundException</h3><p>无法找到目标类。<br>通常加载类的方式：</p>
<blockquote>
<p>Class 类中的 forName 方法。<br>ClassLoader 类中的 findSystemClass 方法。<br>ClassLoader 类中的 loadClass 方法。<br>ClassLoader 类中的 defineClass 方法</p>
</blockquote>
<p>导致该异常的原因通常有以下几种：</p>
<blockquote>
<p>1.类名拼写错误或者没有拼写完整类名（含包名）<br>2.没有导入相应的jar包</p>
</blockquote>
<p>例：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BeanLoadDemo</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">        <span class="comment">//该文件不存在，或者不在此包下。</span></div><div class="line">            Class c = Class.forName(<span class="string">"com.service.util.BeanTest"</span>);</div><div class="line">            c.newInstance();</div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            e.printStackTrace();</div><div class="line">        &#125;</div><div class="line"></div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h3 id="2-ClassNotFoundError"><a href="#2-ClassNotFoundError" class="headerlink" title="2.ClassNotFoundError"></a>2.ClassNotFoundError</h3><p>我们知道一个类在被加载的过程中要经历三个阶段：</p>
<blockquote>
<p>读取：找到.class文件，读取后，存储于方法区<br>链接：校验读取到的.class文件是否符合规范<br>初始化：载入静态资源，静态块，产生一个Class对象</p>
</blockquote>
<p>ClassNotFoundException发生在“读取”阶段。<br>ClassNotFoundError发生在“链接”阶段。<br>两者区别是ClassNotFoundException发生时，可以认为是没有分配内存的，至多是一个byte[]的内存（存放.class字节码）。<br>而ClassNotFoundError会为Class对象准备好内存。</p>
<h3 id="3-NoClassDefFoundError"><a href="#3-NoClassDefFoundError" class="headerlink" title="3.NoClassDefFoundError"></a>3.NoClassDefFoundError</h3><p>当目前执行的类已经编译，但是找不到它的定义时。<br>也就是说你如果编译了一个类B，在类A中调用，编译完成以后，你又删除掉B，运行A的时候那么就会出现这个错误。<br>通常发生在“链接”阶段。</p>
<h3 id="4-关于涉及到类型转换的部分"><a href="#4-关于涉及到类型转换的部分" class="headerlink" title="4.关于涉及到类型转换的部分"></a>4.关于涉及到类型转换的部分</h3><p>这部分应该不属于类加载时可能会发生的异常范畴，不过还是觉得可以说一下，因为它归根结底还是由于类加载引起的。<br>看代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassLoaderDemo</span> <span class="keyword">extends</span> <span class="title">ClassLoader</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> Class <span class="title">define</span><span class="params">(<span class="keyword">byte</span>[] buff)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> defineClass(<span class="keyword">null</span>, buff, <span class="number">0</span>, buff.length);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> <span class="keyword">throws</span> IOException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException </span>&#123;</div><div class="line">        <span class="keyword">int</span> n = <span class="number">0</span>;</div><div class="line">        BufferedInputStream br = <span class="keyword">new</span> BufferedInputStream(</div><div class="line">                <span class="keyword">new</span> FileInputStream(</div><div class="line">                        <span class="keyword">new</span> File(<span class="string">"/Users/admin/OpenService/target/classes/com/service/util/beanfactory/BeanTest.class"</span>)));</div><div class="line">        ByteArrayOutputStream bos = <span class="keyword">new</span> ByteArrayOutputStream();</div><div class="line">        <span class="keyword">while</span> ((n = br.read()) != -<span class="number">1</span>) &#123;</div><div class="line">            bos.write(n);</div><div class="line">        &#125;</div><div class="line">        br.close();</div><div class="line">        <span class="keyword">byte</span>[] buff = bos.toByteArray();</div><div class="line"></div><div class="line">        Class clazz = define(buff);</div><div class="line">        Object o = clazz.newInstance();</div><div class="line">        BeanTest test = (BeanTest)o;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line"><span class="comment">//            new ClassLoaderDemo().read();</span></div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            e.printStackTrace();</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>output:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">init</div><div class="line">java.lang.ClassCastException: com.service.util.beanfactory.BeanTest cannot be cast to com.service.util.beanfactory.BeanTest</div><div class="line">	at com.service.util.beanfactory.ClassLoaderDemo.read(ClassLoaderDemo.java:<span class="number">39</span>)</div><div class="line">	at com.service.util.beanfactory.ClassLoaderDemo.main(ClassLoaderDemo.java:<span class="number">53</span>)</div><div class="line">	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</div><div class="line">	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:<span class="number">62</span>)</div><div class="line">	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:<span class="number">43</span>)</div><div class="line">	at java.lang.reflect.Method.invoke(Method.java:<span class="number">497</span>)</div><div class="line">	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:<span class="number">140</span>)</div></pre></td></tr></table></figure></p>
<p>稍微说明一下，BeanTest这个类中只有一个显示的构造函数（实例化时输出一个“init”），以及一个info 函数（也是简单的输出一个字符串）。<br>这里加载类的方式是直接读取字节码，然后用ClassLoader的 defineClass 方法来加载。</p>
<p>结果抛出的异常时类型转换失败，而且从描述上看，还是自己转换为自己出现异常。<br>为什么会出现这样的异常？<br>由于我们使用的是自定义类加载器直接继承ClassLoader，同时也使用了这个加载器去加载BeanTest  。<br>可以理解为工人A生产了一个产品P。<br>但是在默认情况下，我们自己写的类都是有AppClassLoade来加载的。<br>同样类比于工人头子S生产产品P。<br>在进行类型转换时，这里用的是： BeanTest b = (BeanTest)o;<br>这里出现的“BeanTest” ，又是用AppClassLoader来加载的。<br>那就出现了一个问题，虽然看上去都是产品P，但是是由不同的人生产的。那自然就无法进行转换。于是抛出类型转换异常。<br>根据Class加载的文档资料：</p>
<blockquote>
<p>1.跨ClassLoader访问一些数据是比较麻烦的，但是并不是不能做到，比如JMX2。<br>2.同一个类在同一个ClassLoader中只能加载一次，言下之意就是在不同ClassLoader种可以加载多次。也说明由不同ClassLoader产生的同一个类的Class对象，JVM认识是不同的东西。</p>
</blockquote>
<p>以上两点就能说明这个出现类型转换异常的部分原因。</p>
<h2 id="4-Class的加载过程"><a href="#4-Class的加载过程" class="headerlink" title="4.Class的加载过程"></a>4.Class的加载过程</h2><p>这里从源码调度浅要分析一下一个类的加载过程。</p>
<p>以下是ClassLoader中的一个方法：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> Class&lt;?&gt; loadClass(String name, <span class="keyword">boolean</span> resolve)</div><div class="line">        <span class="keyword">throws</span> ClassNotFoundException</div><div class="line">    &#123;</div><div class="line">        <span class="keyword">synchronized</span> (getClassLoadingLock(name)) &#123;</div><div class="line">            <span class="comment">// 确认该类是否已经被加载，调用的是一个本地方法。</span></div><div class="line">            Class&lt;?&gt; c = findLoadedClass(name);</div><div class="line">            <span class="keyword">if</span> (c == <span class="keyword">null</span>) &#123;</div><div class="line">                <span class="keyword">long</span> t0 = System.nanoTime();</div><div class="line">                <span class="keyword">try</span> &#123;</div><div class="line">                <span class="comment">//parent表示当前加载器的父加载器</span></div><div class="line">                    <span class="keyword">if</span> (parent != <span class="keyword">null</span>) &#123;</div><div class="line">                    <span class="comment">//先由父加载器去尝试加载，同样会进入父加载器的该函数内，继续尝试用其父加载器去加载</span></div><div class="line">                        c = parent.loadClass(name, <span class="keyword">false</span>);</div><div class="line">                    &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    <span class="comment">//如果父加载器不存在，就用根加载器去加载它</span></div><div class="line">                        c = findBootstrapClassOrNull(name);</div><div class="line">                    &#125;</div><div class="line">                &#125; <span class="keyword">catch</span> (ClassNotFoundException e) &#123;</div><div class="line">                   <span class="comment">//抛出异常，找不到该类。</span></div><div class="line">                &#125;</div><div class="line"></div><div class="line">                <span class="keyword">if</span> (c == <span class="keyword">null</span>) &#123;</div><div class="line">                    <span class="comment">//如果还是无法加载Class，则会去调用一个本地方发findClass去加载这个类。</span></div><div class="line">                    <span class="keyword">long</span> t1 = System.nanoTime();</div><div class="line">                    c = findClass(name);</div><div class="line">                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);</div><div class="line">                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);</div><div class="line">                    sun.misc.PerfCounter.getFindClasses().increment();</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">            <span class="keyword">if</span> (resolve) &#123;</div><div class="line">                resolveClass(c);</div><div class="line">            &#125;</div><div class="line">            <span class="keyword">return</span> c;</div><div class="line">        &#125;</div><div class="line">    &#125;</div></pre></td></tr></table></figure></p>
<p>过程：<br>1.负责加载的加载器先去搜寻其已经加载过的类，是否包含目标类。<br>2.若未被加载，询问其父加载器是否加载过<br>3.若父加载器不存在，则有当前加载器尝试进行加载。<br>4.若父加载器加载不了，则用子加载器尝试进行加载。<br>5.若加载成功，返回Class对象，否则抛出异常。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">st=&gt;start: 开始加载</div><div class="line">op=&gt;operation: 返回Class对象</div><div class="line">op4=&gt;operation: 准备工作</div><div class="line">op2=&gt;operation: 尝试加载目标类</div><div class="line">op3=&gt;operation: 抛出异常</div><div class="line">op5=&gt;operation: 进入子加载器</div><div class="line">cond=&gt;condition: 是否已经被加载</div><div class="line">cond2=&gt;condition: 父加载器是否存在</div><div class="line">cond3=&gt;condition: 能否加载</div><div class="line">e=&gt;end</div><div class="line"></div><div class="line">st-&gt;op4-&gt;cond</div><div class="line">cond(yes)-&gt;op-&gt;e</div><div class="line">cond(no)-&gt;cond2</div><div class="line">cond2(no)-&gt;op2</div><div class="line">op2-&gt;cond3</div><div class="line">cond3(yes)-&gt;op</div><div class="line">cond3(no)-&gt;op5-&gt;op2</div><div class="line">cond2(yes)-&gt;op4</div></pre></td></tr></table></figure>
<p>大致流程图如上，画的不好请见谅。</p>
<h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5.总结"></a>5.总结</h2><p>1.ClassLoader的层级结构<br>2.类加载时出现的异常及其原因<br>3.Class加载时的执行流程<br>4.在启动参数内加入 -XX：TraceClassLoading 可以查看启动时被加载的类<br>5.defineClass()对于同名类加载两次就就会报错</p>

      
    </div>

    <div>
      
        

      
    </div>

    <div>
      
        

      
    </div>

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/java/" rel="tag">#java</a>
          
        </div>
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/08/28/spring-ioc-2/" rel="next" title="从源码解析SpringIoc机制（2）">
                <i class="fa fa-chevron-left"></i> 从源码解析SpringIoc机制（2）
              </a>
            
          </div>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/08/28/java-dynamic-porxy/" rel="prev" title="Java动态代理剖析">
                Java动态代理剖析 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div class="ds-thread" data-thread-key="2016/08/28/java-class-load/"
           data-title="" data-url="http://yoursite.com/2016/08/28/java-class-load/">
      </div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel ">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/uploads/touxiang.jpg"
               alt="钱伟峰" />
          <p class="site-author-name" itemprop="name">钱伟峰</p>
          <p class="site-description motion-element" itemprop="description">每天进步一点点</p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">21</span>
              <span class="site-state-item-name">日志</span>
            </a>
          </div>

          
            <div class="site-state-item site-state-categories">
              <a href="/categories">
                <span class="site-state-item-count">7</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">11</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
        </div>

        
        

        
        

      </section>

      
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">
            
              
            
            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-类的加载器简介"><span class="nav-number">1.</span> <span class="nav-text">1.类的加载器简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-自定义类加载器"><span class="nav-number">2.</span> <span class="nav-text">2.自定义类加载器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-加载过程中可能会出现的异常"><span class="nav-number">3.</span> <span class="nav-text">3.加载过程中可能会出现的异常</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-ClassNotFoundException"><span class="nav-number">3.1.</span> <span class="nav-text">1.ClassNotFoundException</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-ClassNotFoundError"><span class="nav-number">3.2.</span> <span class="nav-text">2.ClassNotFoundError</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-NoClassDefFoundError"><span class="nav-number">3.3.</span> <span class="nav-text">3.NoClassDefFoundError</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-关于涉及到类型转换的部分"><span class="nav-number">3.4.</span> <span class="nav-text">4.关于涉及到类型转换的部分</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-Class的加载过程"><span class="nav-number">4.</span> <span class="nav-text">4.Class的加载过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-总结"><span class="nav-number">5.</span> <span class="nav-text">5.总结</span></a></li></ol></div>
            
          </div>
        </section>
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">钱伟峰</span>
</div>

<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Muse
  </a>
</div>

        

        
      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  



  
  <script type="text/javascript" src="/vendors/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/vendors/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/vendors/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/vendors/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/vendors/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/vendors/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.0.1"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.0.1"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.0.1"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.0.1"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.0.1"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"qianweifeng"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
    <script src="/vendors/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>
    <script src="/js/src/hook-duoshuo.js"></script>
  






  
  

  

  

  

</body>
</html>
